home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / utils / fmgr / dfmgr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  8.9 KB  |  348 lines

  1. /*
  2.  * dfmgr.c --
  3.  *    Dynamic function manager code.
  4.  */
  5.  
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <stdio.h>
  9.  
  10. #include "access/heapam.h"
  11. #include "nodes/pg_lisp.h"
  12. #include "utils/builtins.h"    /* for textout() prototype */
  13. #include "utils/fmgr.h"
  14. #include "utils/log.h"
  15.  
  16. #include "tmp/c.h"
  17. #include "port-protos.h"     /* system specific function prototypes */
  18.  
  19. #include "catalog/catname.h"
  20. #include "catalog/syscache.h"
  21. #include "catalog/pg_proc.h"
  22.  
  23. RcsId("$Header: /private/postgres/src/utils/fmgr/RCS/dfmgr.c,v 1.6 1992/05/26 18:45:55 mao Exp $");
  24.  
  25. static DynamicFileList *file_list = NULL;
  26. static DynamicFileList *file_tail = NULL;
  27.  
  28. static ObjectId procedureId_save = -1;
  29. static int pronargs_save;
  30. static func_ptr user_fn_save = NULL;
  31.  
  32. #define NOT_EQUAL(A, B) (((A).st_ino != (B).inode) \
  33.                       || ((A).st_dev != (B).device))
  34.  
  35. func_ptr
  36. fmgr_dynamic(procedureId, pronargs)
  37.     ObjectId    procedureId;
  38.     int         *pronargs;
  39. {
  40.     register    i;
  41.     HeapTuple   procedureTuple;
  42.     struct proc *procedureStruct;
  43.     char        *proname;
  44.     OID         proid, prolang;
  45.     Boolean     proisinh,proistrusted,proiscachable;
  46.     OID         prorettype;
  47.     char        *probinattr, *probinstring;
  48.     func_ptr    user_fn, handle_load();
  49.     char        *uarg[7];
  50.     Relation    rdesc;
  51.     Boolean     isnull;
  52.  
  53.     if (procedureId == procedureId_save)
  54.     {
  55.         *pronargs = pronargs_save;
  56.         return(user_fn_save);
  57.     }
  58.  
  59.     /*
  60.      * The procedure isn't a builtin, so we'll have to do a catalog
  61.      * lookup to find its pg_proc entry.
  62.      */
  63.  
  64.     procedureTuple = SearchSysCacheTuple(PROOID, (char *) procedureId,
  65.                      NULL, NULL, NULL);
  66.     if (!HeapTupleIsValid(procedureTuple)) {
  67.         elog(WARN, "fmgr: Cache lookup failed for procedure %d\n",
  68.              procedureId);
  69.         return(NULL);
  70.     }
  71.  
  72.     procedureStruct = (struct proc *) GETSTRUCT(procedureTuple);
  73.     proname = (procedureStruct)->proname;
  74.     pronargs_save = *pronargs = (procedureStruct)->pronargs;
  75.  
  76.     /*
  77.      * Extract the procedure info from the pg_proc tuple.
  78.      * Since probin is varlena, do a amgetattr() on the procedure
  79.      * tuple.  To do that, we need the rdesc for the procedure
  80.      * relation, so...
  81.      *
  82.      * XXX It may not be wise to turn GC off for this long, but some LISPs 
  83.      *     (e.g., KCL) don't provide a way to protect C-allocated LISP
  84.      *     objects.
  85.      */
  86.  
  87.     /* open pg_procedure */
  88.  
  89.     rdesc = amopenr(ProcedureRelationName->data);
  90.     if (!RelationIsValid(rdesc)) {
  91.         elog(WARN, "fmgr: Could not open relation %s",
  92.              ProcedureRelationName->data);
  93.         return(NULL);
  94.     }
  95.     probinattr = amgetattr(procedureTuple, (Buffer) 0,
  96.                    ProcedureBinaryAttributeNumber,
  97.                    &rdesc->rd_att, &isnull);
  98.     if (!PointerIsValid(probinattr) /*|| isnull*/) {
  99.         amclose(rdesc);
  100.         elog(WARN, "fmgr: Could not extract probin for %d from %s",
  101.              procedureId, ProcedureRelationName->data);
  102.         return(NULL);
  103.     }
  104.     probinstring = textout((struct varlena *)probinattr);
  105.  
  106.     user_fn = handle_load(probinstring, proname);
  107.  
  108.     procedureId_save = procedureId;
  109.     user_fn_save = user_fn;
  110.  
  111.     return(user_fn);
  112. }
  113.  
  114. func_ptr
  115. handle_load(filename, funcname)
  116.  
  117. char *filename, *funcname;
  118.  
  119. {
  120.     DynamicFileList     *file_scanner = NULL;
  121.     DynamicFunctionList *func_scanner, *func_tail = NULL;
  122.     func_ptr            retval = NULL;
  123.     char                *load_error;
  124.     char                *start_addr;
  125.     long                size;
  126.     struct stat  stat_buf;
  127.  
  128.     /*
  129.      * Do this because loading files may screw up the dynamic function
  130.      * manager otherwise.
  131.      *
  132.      */
  133.  
  134.     procedureId_save = -1;
  135.  
  136.     /*
  137.      * Scan the list of loaded FILES to see if the function
  138.      * has been loaded.  
  139.      */
  140.  
  141.     if (filename != NULL)
  142.     {
  143.         for (file_scanner = file_list;
  144.              file_scanner != NULL
  145.              && file_scanner->filename != NULL
  146.              && strcmp(filename, file_scanner->filename) != 0;
  147.              file_scanner = file_scanner->next);
  148.  
  149.         if (file_scanner == NULL)
  150.         {
  151.             if (stat(filename, &stat_buf) == -1)
  152.             {
  153.                 elog(WARN, "stat failed on file %s", filename);
  154.             }
  155.  
  156.             for (file_scanner = file_list;
  157.                  file_scanner != NULL
  158.                  && (NOT_EQUAL(stat_buf, *file_scanner));
  159.                  file_scanner = file_scanner->next);
  160.             /*
  161.              * Same files - different paths (ie, symlink or link)
  162.              */
  163.  
  164.             if (file_scanner != NULL) strcpy(file_scanner->filename, filename);
  165.  
  166.         }
  167.     }
  168.     else
  169.     {
  170.         file_scanner = NULL;
  171.     }
  172.  
  173.     /*
  174.      * File not loaded yet.
  175.      */
  176.  
  177.     if (file_scanner == NULL)
  178.     {
  179.         if (file_list == NULL)
  180.         {
  181.             file_list = (DynamicFileList *)
  182.                         malloc(sizeof(DynamicFileList));
  183.             file_scanner = file_list;
  184.         }
  185.         else
  186.         {
  187.             file_tail->next = (DynamicFileList *)
  188.                                malloc(sizeof(DynamicFileList));
  189.             file_scanner = file_tail->next;
  190.         }
  191.  
  192.         strcpy(file_scanner->filename, filename);
  193.         file_scanner->device = stat_buf.st_dev;
  194.         file_scanner->inode = stat_buf.st_ino;
  195.         file_scanner->next = NULL;
  196.  
  197.         func_scanner = dynamic_file_load(&load_error, filename,
  198.                        &start_addr, &size);
  199.         if (func_scanner == NULL)
  200.         {
  201.             if (file_scanner == file_list)
  202.             {
  203.                 file_list = NULL;
  204.             }
  205.             else
  206.             {
  207.                 file_tail->next = NULL;
  208.             }
  209.  
  210.             free((char *)file_scanner);
  211.             elog(WARN,
  212.                  "Load of file %s failed: %s", filename, load_error);
  213.         }
  214.  
  215.         file_scanner->func_list = func_scanner;
  216.         file_scanner->address = start_addr;
  217.         file_scanner->size = size;
  218.  
  219. /*
  220.  * Just load the file - we are done with that so return.
  221.  */
  222.         file_tail = file_scanner;
  223.  
  224.         if (funcname == NULL) return(NULL);
  225.  
  226.         for (; func_scanner != NULL
  227.              && strcmp(func_scanner->funcname, funcname);
  228.              func_scanner = func_scanner->next);
  229.  
  230.         if (func_scanner == NULL)
  231.         {
  232.             elog(WARN, "Cant find function %s in file %s", funcname, filename);
  233.         }
  234.         else
  235.         {
  236.             retval = func_scanner->func;
  237.         }
  238.     }
  239.     else
  240.     {
  241.         for (func_scanner = file_scanner->func_list;
  242.              func_scanner != NULL
  243.              && strncmp(func_scanner->funcname, funcname, 16);
  244.              func_scanner = func_scanner->next)
  245.         {
  246.             if (func_scanner->next == NULL) func_tail = func_scanner;
  247.         }
  248.  
  249.         if (func_scanner == NULL)
  250.         {
  251.             elog(WARN, "Function %s is not in file %s", funcname, filename);
  252.         }
  253.         else
  254.         {
  255.             retval = func_scanner->func;
  256.         }
  257.     }
  258.     return(retval);
  259. }
  260.  
  261. /*
  262.  * This function loads files by the following:
  263.  *
  264.  * If the file is already loaded:
  265.  * o  Zero out that file's loaded space (so it doesn't screw up linking)
  266.  * o  Free all space associated with that file 
  267.  * o  Free that file's descriptor.
  268.  *
  269.  * Now load the file by calling handle_load with a NULL argument as the
  270.  * function.
  271.  */
  272.  
  273. load_file(filename)
  274.  
  275. char *filename;
  276.  
  277. {
  278.     DynamicFileList *file_scanner, *p;
  279.     struct stat stat_buf;
  280.     int done = 0;
  281.  
  282.     if (stat(filename, &stat_buf) == -1)
  283.     {
  284.         elog(WARN, "load of file %s failed", filename);
  285.     }
  286.  
  287.     if (file_list != NULL && !NOT_EQUAL(stat_buf, *file_list))
  288.     {
  289.         file_scanner = file_list;
  290.         file_list = file_list->next;
  291.         zero_loaded_file(file_scanner);
  292.         free((char *)file_scanner);
  293.     }
  294.     else if (file_list != NULL)
  295.     {
  296.         file_scanner = file_list;
  297.         while (!done)
  298.         {
  299.             if (file_scanner->next == NULL)
  300.             {
  301.                 done = 1;
  302.             }
  303.             else if (!NOT_EQUAL(stat_buf, *(file_scanner->next)))
  304.             {
  305.                 done = 1;
  306.             }
  307.             else
  308.             {
  309.                 file_scanner = file_scanner->next;
  310.             }
  311.         }
  312.  
  313.         if (file_scanner->next != NULL)
  314.         {
  315.             p = file_scanner->next;
  316.             file_scanner->next = file_scanner->next->next;
  317.             zero_loaded_file(p);
  318.             free((char *)p);
  319.         }
  320.     }
  321.     handle_load(filename, NULL);
  322. }
  323.  
  324. zero_loaded_file(file_data)
  325.  
  326. DynamicFileList *file_data;
  327.  
  328. {
  329.     DynamicFunctionList *func_scanner, *throw_away;
  330.  
  331.     bzero(file_data->address, file_data->size);
  332. /*
  333.  * Old DEC dynamic loader uses brk/sbrk - DON'T TRY TO FREE THIS SPACE.
  334.  */
  335.  
  336. #ifndef OLD_DEC
  337.     free((char *)file_data->address);
  338. #endif
  339.     func_scanner = file_data->func_list;
  340.     for (throw_away = func_scanner->next; throw_away != NULL;)
  341.     {
  342.         throw_away = func_scanner->next;
  343.         free((char *)func_scanner);
  344.         func_scanner = throw_away;
  345.     }
  346.     free((char *)file_data->func_list);
  347. }
  348.